#include <stdio.h>
#include <unistd.h>
#include <string.h>
#include <signal.h>

#include "ak_common.h"
#include "ak_vi.h"
#include "ak_md.h"

#define DEFAULT_ISP_CONFIG "/etc/jffs2/"
#define SAVE_FILE_DIR "/mnt/"
#define AREA_H_NUM 4
#define AREA_V_NUM 2

char cfg_dir[100];
static int md_mode = 0;
static int fps = 25;	//msecond
static int detect_time =10;        //demo run time
static int sensitivity = 50;

static void usage(const char *name)
{
	ak_print_normal("Usage: %s [options]\n\n"
		"options:\n"
		"-c sensor cfg file path\n"
		"-m md mode (0: global; 1: area)\n"
		"-t number  test time (second)\n"	
		"-s sensitivity to md ,value [1-100]\n"	
		"-f number   how times to do md each second \n"
		"-h   help\n",name);
}

static void process_signal(int sig)
{ 
	ak_print_notice("\t signal %d caught", sig);
	if((SIGTERM == sig) || (SIGINT == sig) || (SIGSEGV == sig)){
		exit(EXIT_FAILURE);
	}
}

static int register_signal(void)
{
	signal(SIGSEGV, process_signal);
	signal(SIGINT, process_signal);
	signal(SIGTERM, process_signal);	
	signal(SIGCHLD, SIG_IGN);

	return 0;
}

static int match_sensor(void)
{
	if (ak_vi_match_sensor(cfg_dir)) {
		ak_print_error_ex(" match sensor cfg fail!%s\n",cfg_dir);
		return AK_FAILED;
	} else {
		ak_print_normal_ex(" ak_vi_match_sensor ok!\n");
	}

	return AK_SUCCESS;
}

static int init_video_input(void * handle)
{
	struct video_resolution video_res;
	struct video_channel_attr ch_attr ;
	int ret = 0;

	/* get sensor resolution */	
	memset(&video_res,0,sizeof(struct video_resolution));
	if (ak_vi_get_sensor_resolution(handle, &video_res)) 
		ak_print_error_ex("ak_mpi_vi_get_sensor_res fail!\n");
	else
		ak_print_normal_ex("ak_mpi_vi_get_sensor_res ok! w:%d, h:%d\n",
			video_res.width, video_res.height);

	/* set video resolution and  crop information */	
	memset(&ch_attr,0,sizeof(struct video_channel_attr));
	ch_attr.res[VIDEO_CHN_MAIN].width = 1280;
	ch_attr.res[VIDEO_CHN_MAIN].height = 720;
	ch_attr.res[VIDEO_CHN_SUB].width = 640;
	ch_attr.res[VIDEO_CHN_SUB].height = 360;	
	ch_attr.crop.width = 1280;
	ch_attr.crop.height = 720;

	if (ret |= ak_vi_set_channel_attr(handle, &ch_attr)) {
		ak_print_error_ex("ak_vi_set_channel_attr fail!\n");
	} else {
		ak_print_normal_ex("ak_vi_set_channel_attr ok!\n");
	}
	
	memset(&ch_attr,0,sizeof(struct video_channel_attr));
	if (ret |= ak_vi_get_channel_attr(handle, &ch_attr)) {
		ak_print_normal_ex("ak_vi_get_channel_attr fail!\n");
	}	
	
	ak_vi_set_fps(handle, 25);
	 
	int fps = 0; 
	fps = ak_vi_get_fps(handle);
	ak_print_normal_ex("fps = %d\n",fps);
	ret |= ak_vi_capture_on(handle);	
	return ret ;
}

static int move_detect_test(void *vi_handle)
{		
	int ret = -1;
	struct ak_timeval start_tv;
	struct ak_timeval end_tv;
	int md_time;
	
	ak_get_ostime(&start_tv);  
	ak_print_normal_ex("start\n");   		
	      
	if(ak_md_init(&vi_handle) < 0){
		ak_print_error_ex("init fail\n"); 
		return -1;
	}
	if( 0 == md_mode) 
	{
		/*test md in global mode*/
		if(AK_SUCCESS != ak_md_set_global_sensitivity(sensitivity)){ 
			ak_print_error_ex("fail\n"); 
			goto EXIT;
		}
		if(AK_SUCCESS != ak_md_enable(1)){
			ak_print_error_ex("fail\n"); 
			goto EXIT;
		}
		do{
			if(1 == ak_md_get_result(&md_time, NULL, -1))
				ak_print_normal_ex("get md. time:%d\n",md_time); 

			ak_get_ostime(&end_tv);
			/* test time is over and exit */
			if(ak_diff_ms_time(&end_tv, &start_tv) > (detect_time*1000))
				break;
		}while(1);
				
	}else{
		int *area_sens = NULL ;
		int v,h;
		char * pch;
		
		/*test md in area mode*/
		area_sens = calloc(sizeof(int),AREA_V_NUM*AREA_H_NUM); 
		for(v = 0; v < AREA_V_NUM; v++)
			for(h=0 ; h < AREA_H_NUM; h++) 
				*(area_sens+v*AREA_H_NUM+h) = sensitivity;		
    	if(AK_SUCCESS != ak_md_set_area_sensitivity(AREA_H_NUM,AREA_V_NUM,area_sens)){
			ak_print_error_ex("fail\n");
			goto EXIT;
		}
		if(AK_SUCCESS != ak_md_enable(1)){  
			ak_print_error_ex("fail\n"); 
			goto EXIT;
		}		
		pch = (char *)area_sens;
		do{  
			if( 1 == ak_md_get_result(&md_time, pch, -1)){
				ak_print_normal_ex("get md. time:%d\n",md_time); 
				for(v = 0; v < AREA_V_NUM; v++)
					for(h=0 ; h< AREA_H_NUM; h++)
						if(*(pch+v*AREA_H_NUM+h) > 0)
						ak_print_normal_ex("(v %d h %d)%d\n",v,h,*(pch+v*AREA_H_NUM+h)); 
			} 

			ak_get_ostime(&end_tv);
			/* test time is over and exit */
			if(ak_diff_ms_time(&end_tv, &start_tv) > (detect_time*1000))
				break;  
		}while(1);  
		free(area_sens);
		
	}
	ret = 0;
EXIT:
	ak_md_destroy(); 
	ak_print_normal_ex("md exit\n");
   
	return ret;  
}

int main(int argc, char **argv)
{
	void *vi_handle = NULL;

	/* this can be removed */
	register_signal();
	int ch;
	
	ak_print_normal_ex("***md demo compile:%s %s md version:%s*****\n",
		__DATE__,__TIME__,ak_md_get_version());
	
	memset((void *)cfg_dir, 0 ,100);
	/* parse input options */
	while ((ch = getopt(argc,argv,"c:m:t:f:s:h")) != EOF){
		switch(ch){
		case 'c':				
			strncpy(cfg_dir ,optarg , 99);
			break;
		case 'm':				
			md_mode = atoi(optarg);
			break;
		case 't':
			detect_time = atoi(optarg);
			break;			
		case 'f':
			fps = atoi(optarg);
			break;
		case 's':
			sensitivity = atoi(optarg);
			break;
		case 'h':
		case 'H':				
		default:
			usage(argv[0]);
			return 0;
			break;
		}
	}
	
	ak_print_normal_ex("detect_time:%d  fps:%d sensitivity:%d\n",
		detect_time,fps, sensitivity);

	/* set default value if do not provide */
	if(strlen(cfg_dir) == 0)
		strncpy(cfg_dir ,DEFAULT_ISP_CONFIG, 99);

	/* must match sensor before open vi */
	if (match_sensor()) {
		ak_print_error_ex("match sensor fail!\n");
		goto EXIT;
	}
	
	vi_handle = ak_vi_open(VIDEO_DEV0);
	if (NULL == vi_handle) {	
		ak_print_error_ex("ak_vi_open fail!\n");
		goto EXIT;
	} else {
		ak_print_normal_ex("ak_vi_open ok!\n");
	}

	if(init_video_input(vi_handle) != 0){
		ak_print_error_ex("init_video_input fail!\n");
		goto EXIT2;
	} else {
		ak_print_normal_ex("init_video_input ok!\n");
	}
	
    /* test main function */
	move_detect_test(vi_handle);
	
EXIT2:	
	ak_vi_close(vi_handle);
EXIT:
	
	ak_print_normal_ex("###### exit: md demo ######\n");

	return 0;
}
